package cn.edu.jxust.core.domain.repository.impl;

import cn.edu.jxust.common.domain.entity.Account;
import cn.edu.jxust.common.domain.dto.AccountRoleVo;
import cn.edu.jxust.common.domain.dto.AccountVo;
import cn.edu.jxust.common.domain.dto.PasswordVo;
import cn.edu.jxust.common.domain.dto.SlfInfoVo;
import cn.edu.jxust.core.infrastructure.mapper.AccountMapper;
import cn.edu.jxust.core.infrastructure.mapper.AreaMapper;
import cn.edu.jxust.core.infrastructure.mapper.EnterpriseMapper;
import cn.edu.jxust.common.response.Result;
import cn.edu.jxust.common.response.ResultUtils;
import cn.edu.jxust.common.response.enums.ResultStatus;
import cn.edu.jxust.core.domain.repository.AccountService;
import cn.edu.jxust.core.domain.repository.RoleService;
import cn.edu.jxust.core.infrastructure.util.Const;
import cn.edu.jxust.core.infrastructure.util.EncryptionUtil;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author QiuKangming
 * @since 2020-06-29
 * @description
 * 账户操作相关接口, 接口说明: 注意 Account 实体类的MyBatisPlus 维护的逻辑删除取消,需要自己维护 status 字段
 * 账户接口功能:
 * 1. 新增的用户默认角色 id 是0, 且默认是禁用的(status = 0), 需要分配角色之后, 该账户才有用, 所以新增账户的时候, 应该手动把 status 置为0
 * 2.删除账户: 将账户信息的 status 字段改成 0
 * 3. 修改用户的基本信息, 其中密码只能自己账户能改变
 * 4. 查询账户信息
 *    根据名字查找
 *    根据邮箱
 *    根据电话号码
 *    根据添加用户信息的用户名查找
 *    查询用户列表(默认点击的时候就是用户列表)
 */
@Slf4j
@Service
@SuppressWarnings("all")
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {

    private final AccountMapper accountMapper;
    private final AreaMapper areaMapper;
    private final EnterpriseMapper enterpriseMapper;
    private final RoleService roleService;

    @Autowired
    public AccountServiceImpl(AccountMapper accountMapper, AreaMapper areaMapper, EnterpriseMapper enterpriseMapper, RoleService roleService){
        this.accountMapper = accountMapper;
        this.areaMapper = areaMapper;
        this.enterpriseMapper = enterpriseMapper;
        this.roleService = roleService;
    }

    /**
     * 根据账户名获取账户
     * @param accountName 账户名
     * @return Account
     */
    @Override
    public Account getByAccName(String accountName) {

        return accountMapper.getByAccName(accountName);

    }

    /**
     * 分页查询账户信息或者条件查询
     *      根据名字查找
     *      根据邮箱
     *      根据电话号码
     *      企业id
     *      区域id
     *      角色id
     * @param paramMap 参数map集合
     * @param page 第几页
     * @param size 一页几条数据
     * @return IPage<AccountVo>
     */
    @Override
    @Transactional(readOnly = true)
    public Result getAccountVoList(Map<String, String[]> paramMap, Integer page, Integer size) {
        //去除 page size
        paramMap.remove("page");
        paramMap.remove("size");
        //需要过滤掉不必要的参数[防止恶意篡改 url 地址中的参数]
        List<String> parms = new ArrayList<>(Arrays.asList("username", "email", "phone", "area_id", "enterprise_id", "role_id"));
        //如果是超级管理员或者局级, 都可,如果是区级, 不能有area_id,企业用户,不能有area_id,enterprise_id,role_id
        //获取当前用户
        Account currAccount = ((Account) SecurityUtils.getSubject().getPrincipal());
        QueryWrapper<Account> wrapper = new QueryWrapper<>();
        if(currAccount.getRoleId().equals(Const.DISTRICT_ADMIN_ID)) {//区级
            parms.remove(3);
            wrapper.eq("area_id", currAccount.getAreaId());
        }else if(currAccount.getRoleId().equals(Const.ENTERPRISE_USER_ID)) {//企业
            parms.remove(3);
            parms.remove(3);
            parms.remove(3);
            wrapper.eq("area_id", currAccount.getAreaId());
            wrapper.eq("enterprise_id", currAccount.getEnterpriseId());
        }

        //检查查询条件
        AtomicBoolean searchRole = new AtomicBoolean(true);
        paramMap.forEach((k,v)->{
            for (String parm : parms) {
                if(parm.equals(k) && !v[0].equals("")){
                    if(k.equals("role_id")){
                        searchRole.set(false);
                    }
                    wrapper.eq(k,v[0]);
                }
            }
        });
        if(searchRole.get()){
            List<Integer> roleIds = roleService.getRoleIds(currAccount.getRoleId());
            if(roleIds != null && roleIds.size() != 0){
                wrapper.in("role_id", roleIds);
            }
        }
        wrapper.orderByAsc("id");
        IPage<Account> pageInfo1 = accountMapper.selectPage(new Page<>(page, size), wrapper);
        IPage<AccountVo> pageInfo = new Page<>();
        List<Account> accountList = pageInfo1.getRecords();
        List<AccountVo> accountVos = this.toAccountVoList(accountList);

        pageInfo.setCurrent(pageInfo1.getCurrent());
        pageInfo.setRecords(accountVos);
        pageInfo.setPages(pageInfo1.getPages());
        pageInfo.setSize(pageInfo1.getSize());
        pageInfo.setTotal(pageInfo1.getTotal());

        if(pageInfo.getRecords() != null && !pageInfo.getRecords().isEmpty()){
            return ResultUtils.resultWithData(ResultStatus.SUCCESS, pageInfo);
        }else{
            return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "未找到任何用户信息");
        }

    }

    /**
     * 为账户分配角色
     * @param accountRoleVo 账户视图对象
     * @return Result
     */
    @Override
    public Result toAccountRole(AccountRoleVo accountRoleVo) {

        Account account = accountMapper.selectById(accountRoleVo.getUserId());
        if(account == null){
            return ResultUtils.resultWithoutData(ResultStatus.NOT_FOUND, "未找到该用户信息");
        }

        Account currAccount = (Account) SecurityUtils.getSubject().getPrincipal();
        //获取当前角色可操作的角色类型
        List<Integer> roleIds = roleService.getRoleIds(currAccount.getRoleId());
        if(!roleIds.contains(account.getRoleId())){
            log.error("分配角色发生越权, 下级角色尝试修改上级的角色!");
            return ResultUtils.resultWithoutData(ResultStatus.VISITED_FORBID, "无法分配上级的角色");
        }

        //判断是否是禁用账户
        if(accountRoleVo.getRoleId().equals(Const.ACCOUNT_FORBID)){
            account.setRoleId(Const.ACCOUNT_FORBID);
            account.setStatus(Const.ACCOUNT_FORBID);
            return accountMapper.updateById(account) == 1
                    ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "禁用账户成功")
                    : ResultUtils.resultWithoutData(ResultStatus.FAILED, "禁用账户失败");
        }

        /*
         * 分配角色的同时, 启用账户
         */
        account.setRoleId(accountRoleVo.getRoleId());
        account.setStatus(Const.ACCOUNT_USING);

        return accountMapper.updateById(account) == 1
                ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "为用户分配角色成功")
                : ResultUtils.resultWithoutData(ResultStatus.FAILED, "为用户分配角色失败");

    }

    /**
     * 批量删除账户信息
     * @param idsStr 账户id号组成的字符串以 , 分割
     * @return Result
     */
    @Override
    public Result delAccountBatch(String idsStr) {

        String[] ids = idsStr.split(",");
        if(ids.length == 0){
            log.warn("[AccountController --> delAccountBatch]: 警告信息, 传入的 账户 ids 字符串非法!");
            return ResultUtils.resultWithoutData(ResultStatus.FAILED, "请提供合法的参数");
        }
        List<Integer> _ids = new ArrayList<>(ids.length);
        for (String id : ids) {
            _ids.add(Integer.parseInt(id));
        }

        return accountMapper.deleteBatchIds(_ids) > 0
                ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "批量删除用户信息成功")
                : ResultUtils.resultWithoutData(ResultStatus.FAILED, "批量删除用户信息失败");

    }

    /**
     * 修改账户信息
     * @param accountVo 账户试图对象
     * @return Result
     */
    @Override
    public boolean modifyAccount(AccountVo accountVo) {

        Account account = Account.builder()
                .id(accountVo.getId())
                .areaId(accountVo.getAreaId())
                .enterpriseId(accountVo.getEnterpriseId())
                .username(accountVo.getUsername())
                .email(accountVo.getEmail())
                .phone(accountVo.getPhone())
                .createUserid(accountVo.getCreateUserid())
                .build();

        return accountMapper.updateById(account) == 1;

    }

    /**
     * 根据id删除账户信息
     * @param id 账户id
     * @return Result
     */
    @Override
    public Result delAccountById(Integer id) {

        Account account = accountMapper.selectById(id);
        if(null == account){
            log.warn("尝试删除不存在的用户信息, id: {}", id);
            return ResultUtils.resultWithoutData(ResultStatus.FAILED, "待删除的账户信息不存在");
        }
        Account currAccount = (Account) SecurityUtils.getSubject().getPrincipal();
        //获取当前角色可操作的角色类型
        List<Integer> roleIds = roleService.getRoleIds(currAccount.getRoleId());
        if(!roleIds.contains(account.getRoleId())){
            log.error("删除账户发生越权, 下级角色尝试删除上级的账户!");
            return ResultUtils.resultWithoutData(ResultStatus.VISITED_FORBID, "权限不足,无法删除上级账户信息");
        }
        return accountMapper.deleteById(account.getId()) == 1
                ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "删除用户信息成功")
                : ResultUtils.resultWithoutData(ResultStatus.FAILED, "删除用户信息失败");


    }

    /**
     * 添加/注册账户信息
     * @param accountVo 前端视图对象
     * @return boolean
     */
    @Override
    public Result addAccountInfo(AccountVo accountVo) {

        //检查用户名是否存在
        if(isExist(accountVo.getUsername())){
            return ResultUtils.resultWithoutData(ResultStatus.FAILED, "用户名已被注册, 请更换");
        }

        boolean isReg = accountVo.getPassword() == null;
        //添加用户, 分为注册和人工录入情况, 人工录入需要添加录入人的id号, 可以直接判断前端传过来的对象的
        //createUserid 值是否为 null
        //添加用户: 分为超级管理员和局级管理员添加(区域和企业id都为0), 区级管理员添加, 企业用户添加(区域和企业id分别是自己的)
        Account account = Account.builder()
                .id(accountVo.getId())
                .roleId(0)
                .username(accountVo.getUsername())
                .password(isReg ? EncryptionUtil.encrypt(Const.DEFAULT_ACCOUNT_PASSWORD) : EncryptionUtil.encrypt(accountVo.getPassword()))
                .email(accountVo.getEmail())
                .phone(accountVo.getPhone())
                .createUserid(accountVo.getCreateUserid())
                .status(Const.ACCOUNT_FORBID)
                .build();

        if(isReg){//添加用户
            //获取当前用户
            Account curr = (Account) SecurityUtils.getSubject().getPrincipal();
            if(curr.getRoleId().equals(Const.DISTRICT_ADMIN_ID)){
                account.setAreaId(curr.getAreaId());
                account.setEnterpriseId(accountVo.getEnterpriseId());
            }else if(curr.getEnterpriseId().equals(Const.ENTERPRISE_USER_ID)){
                account.setAreaId(curr.getAreaId());
                account.setEnterpriseId(curr.getEnterpriseId());
            }/*else{//超管和局级
                if(accountVo.getAreaId() != null){
                    account.setAreaId(accountVo.getAreaId());
                }else{
                    return ResultUtils.resultWithoutData(ResultStatus.FAILED, "请选择区域信息");
                }
                if(accountVo.getEnterpriseId() != null){
                    account.setEnterpriseId(accountVo.getEnterpriseId());
                }else{
                    return ResultUtils.resultWithoutData(ResultStatus.FAILED, "请选择企业信息");
                }
            }*/
        }

        int val = accountMapper.insert(account);
        //判断是注册还是添加
        String msg = isReg ? "添加" : "注册";
        if(val == 1){
            return ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "成功" + msg + "用户");
        }else{
            return ResultUtils.resultWithoutData(ResultStatus.FAILED, msg + "用户失败");
        }

    }

    /**
     * 根据账户名称获取账户视图对象
     * @param name 账户名称
     * @return AccountVo
     */
    @Override
    public AccountVo toAccountVo(String name) {

        Account account = this.getByAccName(name);
        if(null != account){
            AccountVo accountVo = new AccountVo();
            BeanUtil.copyProperties(account, accountVo);
            //2. 填充其他字段: roleName, areaName, enterpriseName, createUserid
            accountVo.setRoleName(roleService.getRoleNameById(account.getRoleId()));
            accountVo.setAreaName(areaMapper.getAreaNameById(accountVo.getAreaId()));
            accountVo.setEnterpriseName(enterpriseMapper.getEnterNameById(accountVo.getAreaId(), accountVo.getEnterpriseId()));
            accountVo.setCreateUserName(accountMapper.getAccNameById(accountVo.getCreateUserid()));
            return accountVo;
        }
        return null;

    }

    /**
     * 判断用户是否存在
     * @param username 用户名
     * @return boolean
     */
    @Override
    public boolean isExist(String username) {

        return accountMapper.isExist(username) == 1;

    }

    /**
     * 重置用户密码
     * @param username 用户名
     * @return Result
     */
    @Override
    public Result resetPwd(String username) {

        Account obj = getByAccName(username);
        if(null == obj){
            return ResultUtils.resultWithoutData(ResultStatus.USER_NOT_FOUND, "用户不存在, 无法重置密码");
        }
        if(obj.getStatus().equals(Const.ACCOUNT_FORBID)){
            return ResultUtils.resultWithoutData(ResultStatus.USER_DISABLE, "该用户已被禁用, 无法重置密码");
        }
        //用户状态正常
        return accountMapper.
                resetPwd(EncryptionUtil.encrypt(Const.DEFAULT_ACCOUNT_PASSWORD),
                        username, Const.ACCOUNT_USING) == 1
                ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "成功重置密码")
                : ResultUtils.resultWithoutData(ResultStatus.FAILED, "重置密码失败, 请重试");

    }

    /**
     * 修改个人信息
     * @param slfInfo 个人信息视图对象
     * @return Result
     */
    @Override
    public Result modifySelfInfo(SlfInfoVo slfInfo) {

        Account obj = accountMapper.selectById(slfInfo.getId());
        if(null != obj){
            //如果不是原始用户名, 判断该用户名是否有效, 如果是原始用户名不做处理
            if(!obj.getUsername().equals(slfInfo.getUsername())){
                if(isExist(slfInfo.getUsername())) {
                    return ResultUtils.resultWithoutData(ResultStatus.FAILED, "该用户名已被注册, 请重更换用户名");
                }
            }

            //重新设置信息
            obj.setUsername(slfInfo.getUsername());
            obj.setEmail(slfInfo.getEmail());
            obj.setPhone(slfInfo.getPhone());
            return accountMapper.updateById(obj) == 1
                    ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "个人信息更新成功")
                    : ResultUtils.resultWithoutData(ResultStatus.FAILED, "个人信息更新失败, 请重试");

        }else {
            return ResultUtils.resultWithoutData(ResultStatus.FAILED, "您提供的信息有误, 请重试");
        }

    }

    @Override
    public Result modifySelfPwd(PasswordVo passwordVo) {

        Account obj = accountMapper.selectById(passwordVo.getId());

        if(obj != null){
            //原始密码正确, 如果原始密码与新密码一样, 则不成功
            if(passwordVo.getOldpassword().equals(passwordVo.getPassword())){
                return ResultUtils.resultWithoutData(ResultStatus.FAILED, "原密码与新密码一样, 请重新输入");
            }
            //校验原始密码
            if(!EncryptionUtil.encrypt(passwordVo.getOldpassword()).equals(obj.getPassword())){
                return ResultUtils.resultWithoutData(ResultStatus.FAILED, "您输入的原密码不正确, 请重新输入");
            }
            //原始密码正确, 更新密码
            obj.setPassword(EncryptionUtil.encrypt(passwordVo.getPassword()));
            return accountMapper.updateById(obj) == 1
                    ? ResultUtils.resultWithoutData(ResultStatus.SUCCESS, "密码修改成功")
                    : ResultUtils.resultWithoutData(ResultStatus.FAILED, "密码修改失败, 请重试");

        }else{
            return ResultUtils.resultWithoutData(ResultStatus.FAILED, "您提供的信息有误, 请重试");
        }

    }

    /**
     * 将 List<Account> 转换成 List<AccountVo>
     * @param accounts 账户对象
     * @return List<AccountVo>
     */
    private List<AccountVo> toAccountVoList(List<Account> accounts){

        //声明变量
        List<AccountVo> accountVos = new ArrayList<>(accounts.size());
        //遍历企业列表
        accounts.forEach(account -> accountVos.add(toAccountVo(account)));
        return accountVos;

    }

    /**
     * 将 Account 转换成 AccountVo
     * @param account 账户视图对象
     * @return AccountVo
     */
    @Override
    public AccountVo toAccountVo(Account account){

        //声明变量
        AccountVo accountVo = new AccountVo();
        BeanUtil.copyProperties(account, accountVo);
        //2. 填充其他字段: roleName, areaName, enterpriseName, createUserid
        if(account.getRoleId().equals(0)){
            accountVo.setRoleName("未分配角色(已禁用)");
        }else{
            accountVo.setRoleName(roleService.getRoleNameById(account.getRoleId()));
        }
        accountVo.setAreaName(areaMapper.getAreaNameById(accountVo.getAreaId()));
        accountVo.setEnterpriseName(enterpriseMapper.getEnterNameById(accountVo.getAreaId(), accountVo.getEnterpriseId()));
        accountVo.setCreateUserName(accountMapper.getAccNameById(accountVo.getCreateUserid()));
        return accountVo;

    }

}
